#include "Inventory.h"

#include "boost/lexical_cast.hpp"
#include "Conversions.h"
#include "Item.h"
#include "Logger.h"
#include "Singleton.h"
#include "ItemDatabase.h"
#include "ResourceDatabase.h"
Inventory::Inventory(int inventoryBgId)
: initialised(false)
, show(false)
, invBg(inventoryBgId)
, rows(4)
, columns(8)
, isDragged(false)
, wasLeftDown(false)
, wasDragged(false)
{
    invFont.LoadFromFile("data/gui/fonts/arial.ttf");
    itemsInStack = sf::Text("", invFont, 12);
    itemsInStack.SetColor(sf::Color::Red);
}




void Inventory::cleanUp()
{
    BEGIN_CLEAN_UP("Inventory");

    items.clear();

    END_CLEAN_UP("Inventory");
}


const ItemStack& Inventory::getStack(int item_id)
{
    items_map::const_iterator item = items.find(item_id);
    if(item == items.end())
    {
        throw std::runtime_error("Invalid item ID (" +
            Conversions::toString(item_id) +
            ") in Inventory::getData().");
    }
    return item->second;
}

const ItemStack& Inventory::getStack(const Item& item)
{
    return getStack(item.getId());
}

void Inventory::addItem(const ItemPtr& item, size_t numberToAdd )
{
    std::map<int, ItemStack>::iterator it;
    for (it = items.begin() ; it != items.end() && numberToAdd != 0; it++)
    {
        if ((*it).second.getItem()->getId() == item->getId() && (*it).second.getStack() != (*it).second.getMaxStack())
        {
            numberToAdd = (*it).second.addItems(numberToAdd);
        }
    }
    if (items.size() < columns * rows)
    {
        if (numberToAdd > 0)
        {        
            std::map<int, ItemStack>::iterator it;
            int i = -1;
            for(int j = 0; j < items.size() + 1; ++j)
            {
                if (items.end() == items.find(j))
                {
                    i = j;
                    break;
                }
                
            }
            if (i != -1)
            {
                int tmpNumberToAdd;
                (numberToAdd > ItemDatabase::get().getData(item->getId()).getMaxStack()) 
                    ? tmpNumberToAdd = ItemDatabase::get().getData(item->getId()).getMaxStack()
                    : tmpNumberToAdd = numberToAdd;
                items.insert(std::pair<int, ItemStack>(i, ItemStack(item, tmpNumberToAdd, (size_t)ItemDatabase::get().getData(item->getId()).getMaxStack())));
                items[items.size()-1].getIcon()->SetPosition(14 + ((items.size() - 1) % columns * 35), 300 + ((items.size() - 1) / columns * 35));
                numberToAdd -= ItemDatabase::get().getData(item->getId()).getMaxStack();
                if (numberToAdd > 0)
                {
                    addItem(item, numberToAdd);
                }
            }
        }
    }
}

void Inventory::render( sf::RenderWindow& window )
{
    if (show)
    {
        std::map<int, ItemStack>::iterator it;
        window.Draw(invBg);
        for(it = items.begin() ; it != items.end(); it++)
        {

            itemsInStack.SetString(boost::lexical_cast<std::string>((*it).second.getStack()));
            itemsInStack.SetPosition(invBg.GetPosition() + sf::Vector2f(32 + ((*it).first % columns * 35), 318 + ((*it).first / columns * 35)));
            window.Draw(*(*it).second.getIcon());
            window.Draw(itemsInStack);
        }
    }
}

void Inventory::swapShow()
{
    show = (show) ? false : true;
}

bool Inventory::getShow()
{
    return show;
}

void Inventory::setShow( bool show )
{
    show = show;
}

void Inventory::update( sf::RenderWindow& window )
{
    if ((!wasLeftDown) &&
        (window.GetInput().IsMouseButtonDown(sf::Mouse::Left)) &&
        (window.GetInput().GetMouseX() >= invBg.GetPosition().x) &&
        (window.GetInput().GetMouseX() <= invBg.GetPosition().x + invBg.GetImage()->GetWidth()) &&
        (window.GetInput().GetMouseY() >= invBg.GetPosition().y) &&
        (window.GetInput().GetMouseY() <= invBg.GetPosition().y + 15))
    {
        isDragged = true;
    }    
    if ((wasLeftDown) && (!window.GetInput().IsMouseButtonDown(sf::Mouse::Left)))
    {
        isDragged = false;
        wasDragged = false;
    }
    if (isDragged)
    {
        if (wasDragged)
        {
            move(sf::Vector2i(window.GetInput().GetMouseX(), window.GetInput().GetMouseY()) - lastMousePosition);
        }
        lastMousePosition.x = window.GetInput().GetMouseX();
        lastMousePosition.y = window.GetInput().GetMouseY();
        wasDragged = true;
    }
    if ((window.GetInput().GetMouseX() >= invBg.GetPosition().x) &&
        (window.GetInput().GetMouseX() <= invBg.GetPosition().x + invBg.GetImage()->GetWidth()) &&
        (window.GetInput().GetMouseY() >= invBg.GetPosition().y) &&
        (window.GetInput().GetMouseY() <= invBg.GetPosition().y + 15))
    {
        if ((window.GetInput().IsMouseButtonDown(sf::Mouse::Left)) && (!wasLeftDown))
        {
            wasLeftDown = true;
        }
        else if (!window.GetInput().IsMouseButtonDown(sf::Mouse::Left))
        {
            wasLeftDown = false;
        }
    }
    if ((window.GetInput().IsMouseButtonDown(sf::Mouse::Left)) && (!wasLeftDown))
    {
        wasLeftDown = true;
    }
}

void Inventory::move( sf::Vector2i move )
{
    invBg.Move((sf::Vector2f)move);
    for(int i = 0; i < items.size(); ++i)
    {
        items[i].getIcon()->Move((sf::Vector2f)move);
    }
}

AnimatedSprite Inventory::getBgSprite() const
{
    return invBg;
}
//void ItemDatabase::readFile(fileName)
//{
//}
//
//void ItemDatabase::writeFile(fileName) const
//{
//}